#include "CodeParser.hpp"
#include "UtilityParsers.hpp"
#include "Value.hpp"

CodeParser::CodeParser(InputStream * stream)
: Object()
, stream_(stream)
, value_()
, location_()
{

}

CodeParser::~CodeParser()
{
} 

int CodeParser::parseNext()
{
	value_ = ObjectPtr();
	location_ = SourceLocation();

	{
		InputGetter g(stream_);
		g.discard();
	
		if(g.eof()) return 0;

		char c = g.ch();
		if(isspace(c)) 
			goto m_spaces;
		if(c == '\"' || c == '\'')
			goto m_string;
		if(isdigit(c))
			goto m_number;
		if(isalpha(c))
			goto m_name;
		else
			goto m_operator;
	}
m_spaces:
	return parseSpaces();
m_string:
	return parseString();
m_number:
	return parseNumber();
m_name:
	return parseName();
m_operator:
	return parseOperator();	
}


int CodeParser::parseSpaces()
{
	for(bool init = true;;)
	{
		InputGetter g(stream_);
		if(init) stream_->startParsing();
		if(g.eof()) break;
		char c = g.ch();
		if(!isspace(c) || c == '\n')
		{
			g.discard();
			break;
		}
	}
	location_ = stream_->location();
	return 0;
}

int CodeParser::parseName()
{
	static struct {
		char const * keyword;
		int tokenId;
	} const keywordTable[] = 
	{
		{ "if",     yy::parser::token::KEYWORD_IF },
		{ "elif",   yy::parser::token::KEYWORD_ELIF },
		{ "else",   yy::parser::token::KEYWORD_ELSE },
		{ "end",    yy::parser::token::KEYWORD_END },
		{ "for",    yy::parser::token::KEYWORD_FOR },
		{ "next",   yy::parser::token::KEYWORD_NEXT },
		{ "while",  yy::parser::token::KEYWORD_WHILE },
		{ "repeat", yy::parser::token::KEYWORD_REPEAT }
	};
	static int const keywordCount = sizeof(keywordTable) / sizeof(keywordTable[0]);

	NameParser name(stream_);
	location_ = name.location();

	String str = name.name();
	for(int i=0; i<keywordCount; ++i)
	{
		if(str == keywordTable[i].keyword)
		{
			return keywordTable[i].tokenId;
		}
	}

	if(str == "true")
	{
		value_ = new BoolValue(true);
		return yy::parser::token::LITERAL;
	}
	if(str == "false")
	{
		value_ = new BoolValue(false);
		return yy::parser::token::LITERAL;
	}

	value_ = new StrValue(str);
	return yy::parser::token::NAME;
}


int CodeParser::parseString()
{
	StringParser string(stream_);
	location_ = string.location();
	value_ = new StrValue(string.string());
	return yy::parser::token::LITERAL;
}

int CodeParser::parseNumber()
{
	NumberParser number(stream_);
	location_ = number.location();
	value_ = new IntValue(number.intValue());
	return yy::parser::token::LITERAL;
}

int CodeParser::parseOperator()
{
	OperatorParser op(stream_);
	location_ = op.location();
	String str = op.string();

	if(str == ";" || str == "(" || str == ")" || str == "=" || str == ",")
	{
		return (int)str.at(0);
	}

	value_ = new StrValue(str);

	if(str == "<" || str == ">" || str == "<="
		|| str == ">=" || str == "==" || str == "!="
		)
	{
		return yy::parser::token::OP_BINARY_0;
	}

	if(str == "+" || str =="-")
	{
		return yy::parser::token::OP_XNARY;
	}

	if(str == "|" || str == "^" || str == "$")
	{
		return yy::parser::token::OP_BINARY_1;
	}

	if(str == "*" || str == "/" || str == "%"
		|| str == "&" || str == "<<" || str == ">>"
		)
	{
		return yy::parser::token::OP_BINARY_2;
	}

	if(str == "~" || str =="!")
	{
		return yy::parser::token::OP_UNARY;
	}

	return yy::parser::token::OP_ASSIGN;
}
